package com.ruoyi.jihuo.api;

import com.ruoyi.jihuo.domain.JhTmAccount;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class TaoApi2 implements TaoApi {
    private static final Logger log = LoggerFactory.getLogger(TaoApi2.class);

    @Override
    public String callTaoApi(String api, Map<String, Object> paramMap, JhTmAccount jhTmAccount) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // common parameters
        String appKey = jhTmAccount.getJhAppKey();
        String session = jhTmAccount.getJhAppSession();
        String timestamp = sdf.format(new Date());
        String v = "2.0";
        String sign_method = "md5";
        String format = "json";

        Map<String, Object> params = getStringObjectMap(api, paramMap, appKey, session, timestamp, sign_method, v, format);
        String appSecret = jhTmAccount.getJhAppSecret();

        String sign = signTopRequest(params, appSecret, sign_method);
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();

        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        String queryString = null;
        try {
            queryString = "app_key=" + URLEncoder.encode(appKey, "UTF-8") + "&" +
                    "method=" + URLEncoder.encode(api, "UTF-8") + "&" +
                    "session=" + URLEncoder.encode(session, "UTF-8") + "&" +
                    "sign=" + URLEncoder.encode(sign, "UTF-8") + "&" +
                    "sign_method=" + URLEncoder.encode(sign_method, "UTF-8") + "&" +
                    "v=" + URLEncoder.encode(v, "UTF-8") + "&" +
                    "format=" + URLEncoder.encode(format, "UTF-8") + "&" +
                    paramMap2String(paramMap) +
                    "timestamp=" + URLEncoder.encode(timestamp, "UTF-8") + "&";
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        RequestBody requestBody = RequestBody.create(mediaType, queryString);
        Request request = new Request.Builder()
                .url("http://jihuo.luckhua.cn/ApiService/RouterJson")
                .method("POST", requestBody)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();
        String responseBodyString = null;
        try {
            Response response = client.newCall(request).execute();
            responseBodyString = "";
            if (response.isSuccessful()) {
                ResponseBody responseBody = response.body();
                if (responseBody != null) {
                    responseBodyString = responseBody.string(); // 一次性读取全部内容
                    // 使用 responseBodyString 进行后续处理
                    System.out.println(responseBodyString);
                }
            }
        } catch (IOException e) {
            log.error("IOException: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        return responseBodyString;
    }

    @Override
    public String uploadImage(String api, Map<String, Object> paramMap, JhTmAccount jhTmAccount) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // common parameters
        String appKey = jhTmAccount.getJhAppKey();
        String session = jhTmAccount.getJhAppSession();
        String timestamp = sdf.format(new Date());
        String v = "2.0";
        String sign_method = "md5";
        String format = "json";

        Map<String, Object> params = getStringObjectMap(api, paramMap, appKey, session, timestamp, sign_method, v, format);
        String appSecret = jhTmAccount.getJhAppSecret();
        String sign = signTopRequest(params, appSecret, sign_method);
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        MediaType mediaType = MediaType.parse("text/plain");
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        params.forEach((key, value) -> {
            if (value instanceof byte[]) {
                builder.addFormDataPart(key, "fileName", RequestBody.create(MediaType.parse("application/octet-stream"), (byte[]) value));
            } else {
                builder.addFormDataPart(key, value.toString());
            }
        });
        builder.addFormDataPart("sign", sign);
        MultipartBody body = builder.build();
        Request request = new Request.Builder()
                .url("http://jihuo.luckhua.cn/ApiService/RouterJson")
                .method("POST", body)
                .build();
        String responseBodyString = null;
        try {
            Response response = client.newCall(request).execute();
            responseBodyString = "";
            if (response.isSuccessful()) {
                ResponseBody responseBody = response.body();
                if (responseBody != null) {
                    responseBodyString = responseBody.string(); // 一次性读取全部内容
                    // 使用 responseBodyString 进行后续处理
                    System.out.println(responseBodyString);
                }
            }
        } catch (IOException e) {
            log.error("上传图片异常: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        return responseBodyString;
    }

    private static Map<String, Object> getStringObjectMap(String api, Map<String, Object> paramMap, String appKey, String session, String timestamp, String sign_method, String v, String format) {
        Map<String, Object> params = new HashMap<>();
        params.put("method", api);
        params.put("app_key", appKey);
        params.put("session", session);
        params.put("timestamp", timestamp);
        params.put("sign_method", sign_method);
        params.put("v", v);
        params.put("format", format);
        params.putAll(paramMap);
        return params;
    }

    private String paramMap2String(Map<String, Object> paramMap) {
        StringBuilder queryString = new StringBuilder();
        paramMap.forEach((k, v) -> {
            if (v instanceof byte[]) {
                return;
            }
            if (StringUtils.isNotBlank(k) && v != null) {
                try {
                    queryString.append(k).append("=").append(URLEncoder.encode(v.toString(), "UTF-8")).append("&");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        return queryString.toString();
    }

    private String byte2Str(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        sign.append("[");
        for (byte aByte : bytes) {
            sign.append(aByte).append(",");
        }
        sign.deleteCharAt(sign.length() - 1);
        sign.append("]");
        return sign.toString();
    }

    private String signTopRequest(Map<String, Object> params, String secret, String signMethod) {
        // 第一步：检查参数是否已经排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);

        // 第二步：把所有参数名和参数值串在一起
        StringBuilder query = new StringBuilder();
        if ("md5".equals(signMethod)) { //签名的摘要算法，可选值为：hmac，md5，hmac-sha256
            query.append(secret);
        }
        for (String key : keys) {
            Object value = params.get(key);
            if (value instanceof byte[]) {
                continue;
            }
            if (value == null) {
                log.warn("参数为空，自动跳过：" + key + "=" + value + "");
                continue;
            } else {
                if (StringUtils.isNoneBlank(key, value.toString())) {
                    query.append(key).append(value.toString());
                }
            }
        }

        // 第三步：使用MD5/HMAC加密
        byte[] bytes;
        if ("hmac".equals(signMethod)) {
            bytes = encryptHMAC(query.toString(), secret);
        } else {
            query.append(secret);
            bytes = encryptMD5(query.toString());
        }

        // 第四步：把二进制转化为大写的十六进制(正确签名应该为32大写字符串，此方法需要时使用)
        return byte2hex(bytes);
    }

    private byte[] encryptHMAC(String data, String secret) {
        byte[] bytes = null;
        try {
            SecretKey secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacMD5");
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        } catch (GeneralSecurityException gse) {
            throw new RuntimeException(gse.toString());
        }
        return bytes;
    }

    private byte[] encryptMD5(String data) {
        return encryptMD5(data.getBytes(StandardCharsets.UTF_8));
    }

    private byte[] encryptMD5(byte[] data) {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data);
        } catch (GeneralSecurityException gse) {
            throw new RuntimeException(gse.toString());
        }
        return bytes;
    }

    private String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

}
